Code Coverage
 
Classes and Traits
Functions and Methods
Lines
Total
0.00% covered (danger)
0.00%
0 / 1
91.67% covered (success)
91.67%
11 / 12
CRAP
96.88% covered (success)
96.88%
62 / 64
UserPreferencesSubscriber
0.00% covered (danger)
0.00%
0 / 1
91.67% covered (success)
91.67%
11 / 12
26
96.88% covered (success)
96.88%
62 / 64
 setContainer
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
2 / 2
 getSubscribedEvents
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
1 / 1
 onFlush
100.00% covered (success)
100.00%
1 / 1
3
100.00% covered (success)
100.00%
7 / 7
 postFlush
100.00% covered (success)
100.00%
1 / 1
2
100.00% covered (success)
100.00%
4 / 4
 preRemove
100.00% covered (success)
100.00%
1 / 1
4
100.00% covered (success)
100.00%
5 / 5
 preUpdate
100.00% covered (success)
100.00%
1 / 1
4
100.00% covered (success)
100.00%
5 / 5
 getMetadata
100.00% covered (success)
100.00%
1 / 1
2
100.00% covered (success)
100.00%
4 / 4
 computeChangeset
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
3 / 3
 onChannelRemoved
100.00% covered (success)
100.00%
1 / 1
2
100.00% covered (success)
100.00%
10 / 10
 onTreeRemoved
0.00% covered (danger)
0.00%
0 / 1
2.03
80.00% covered (warning)
80.00%
8 / 10
 onLocalesDeactivated
100.00% covered (success)
100.00%
1 / 1
3
100.00% covered (success)
100.00%
12 / 12
 findUsersBy
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
1 / 1
<?php
namespace Akeneo\UserManagement\Bundle\EventListener;
use Akeneo\Channel\Component\Model\ChannelInterface;
use Akeneo\Channel\Component\Model\LocaleInterface;
use Akeneo\Tool\Component\Classification\Model\CategoryInterface;
use Doctrine\Common\EventSubscriber;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Event\OnFlushEventArgs;
use Doctrine\ORM\Event\PostFlushEventArgs;
use Doctrine\ORM\UnitOfWork;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
 * Aims to add/remove locales, channels and trees to user preference choices
 *
 * @author    Nicolas Dupont <nicolas@akeneo.com>
 * @copyright 2013 Akeneo SAS (http://www.akeneo.com)
 * @license   http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
 */
class UserPreferencesSubscriber implements EventSubscriber
{
    /** @var ContainerInterface */
    protected $container;
    /** @var array */
    protected $metadata = [];
    /** @var array */
    protected $deactivatedLocales = [];
    /**
     * Inject service container
     *
     * @param ContainerInterface $container
     *
     * @return UserPreferencesSubscriber
     */
    public function setContainer($container)
    {
        $this->container = $container;
        return $this;
    }
    /**
     * Specifies the list of events to listen
     *
     * @return array
     */
    public function getSubscribedEvents()
    {
        return [
            'onFlush',
            'postFlush',
        ];
    }
    /**
     * On flush
     *
     * @param OnFlushEventArgs $args
     */
    public function onFlush(OnFlushEventArgs $args)
    {
        $manager = $args->getEntityManager();
        $uow = $manager->getUnitOfWork();
        foreach ($uow->getScheduledEntityUpdates() as $entity) {
            $this->preUpdate($uow, $entity);
        }
        foreach ($uow->getScheduledEntityDeletions() as $entity) {
            $this->preRemove($uow, $manager, $entity);
        }
    }
    /**
     * Post flush
     *
     * @param PostFlushEventArgs $args
     */
    public function postFlush(PostFlushEventArgs $args)
    {
        $manager = $args->getEntityManager();
        if (!empty($this->deactivatedLocales)) {
            $this->onLocalesDeactivated($manager);
        }
    }
    /**
     * Before remove
     *
     * @param UnitOfWork             $uow
     * @param EntityManagerInterface $manager
     * @param object                 $entity
     */
    protected function preRemove(UnitOfWork $uow, EntityManagerInterface $manager, $entity)
    {
        if ($entity instanceof ChannelInterface) {
            $this->onChannelRemoved($uow, $manager, $entity);
        }
        if ($entity instanceof CategoryInterface && $entity->isRoot()) {
            $this->onTreeRemoved($uow, $manager, $entity);
        }
    }
    /**
     * Before update
     *
     * @param object $entity
     */
    protected function preUpdate(UnitOfWork $uow, $entity)
    {
        if ($entity instanceof LocaleInterface && !$entity->isActivated()) {
            $changeset = $uow->getEntityChangeSet($entity);
            if (isset($changeset['activated'])) {
                $this->deactivatedLocales[] = $entity->getCode();
            }
        }
    }
    /**
     * Get the metadata of an entity
     *
     * @param EntityManagerInterface $manager
     * @param object                 $entity
     *
     * @return array
     */
    protected function getMetadata(EntityManagerInterface $manager, $entity)
    {
        $className = get_class($entity);
        if (!isset($this->metadata[$className])) {
            $this->metadata[$className] = $manager->getClassMetadata($className);
        }
        return $this->metadata[$className];
    }
    /**
     * Compute changeset
     *
     * @param UnitOfWork             $uow
     * @param EntityManagerInterface $manager
     * @param object                 $entity
     */
    protected function computeChangeset(UnitOfWork $uow, EntityManagerInterface $manager, $entity)
    {
        $uow->persist($entity);
        $uow->computeChangeSet($this->getMetadata($manager, $entity), $entity);
    }
    /**
     * Update catalog scope of users using a channel that will be removed
     *
     * @param UnitOfWork             $uow
     * @param EntityManagerInterface $manager
     * @param ChannelInterface       $channel
     */
    protected function onChannelRemoved(
        UnitOfWork $uow,
        EntityManagerInterface $manager,
        ChannelInterface $channel
    ) {
        $users = $this->findUsersBy(['catalogScope' => $channel]);
        $scopes = $this->container->get('pim_catalog.repository.channel')->findAll();
        $defaultScope = current(
            array_filter(
                $scopes,
                function ($scope) use ($channel) {
                    return $scope->getCode() !== $channel->getCode();
                }
            )
        );
        foreach ($users as $user) {
            $user->setCatalogScope($defaultScope);
            $this->computeChangeset($uow, $manager, $user);
        }
    }
    /**
     * Update default tree of users using a tree that will be removed
     *
     * @param CategoryInterface $category
     */
    protected function onTreeRemoved(UnitOfWork $uow, EntityManagerInterface $manager, CategoryInterface $category)
    {
        $users = $this->findUsersBy(['defaultTree' => $category]);
        $trees = $this->container->get('pim_catalog.repository.category')->getTrees();
        $defaultTree = current(
            array_filter(
                $trees,
                function ($tree) use ($category) {
                    return $tree->getCode() !== $category->getCode();
                }
            )
        );
        foreach ($users as $user) {
            $user->setDefaultTree($defaultTree);
            $this->computeChangeset($uow, $manager, $user);
        }
    }
    /**
     * Update catalog locale of users using a deactivated locale
     */
    protected function onLocalesDeactivated(EntityManagerInterface $manager)
    {
        $localeRepository = $this->container->get('pim_catalog.repository.locale');
        $activeLocales = $localeRepository->getActivatedLocales();
        $defaultLocale = current($activeLocales);
        foreach ($this->deactivatedLocales as $localeCode) {
            $deactivatedLocale = $localeRepository->findOneByIdentifier($localeCode);
            $users = $this->findUsersBy(['catalogLocale' => $deactivatedLocale]);
            foreach ($users as $user) {
                $user->setCatalogLocale($defaultLocale);
                $manager->persist($user);
            }
        }
        $this->deactivatedLocales = [];
        $manager->flush();
    }
    /**
     * Return users matching the specified criteria
     *
     * @param array $criteria
     *
     * @return array
     */
    protected function findUsersBy(array $criteria)
    {
        return $this->container->get('pim_user.manager')->getRepository()->findBy($criteria);
    }
}